#include <netinet/in.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>

#define SERV_PORT          8000
#define MAXLINE            4096

typedef struct sockaddr SA;


static int Socket(int domain, int type, int protocol);
static int Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
static ssize_t Recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
static ssize_t Sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
static int  Inet_pton(int af, const char *src, void *dst);
static void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen);

static int Fputs(const char *s, FILE *stream);
static char *Fgets(char *s, int size, FILE *stream);



int main(int argc, char *argv[]) 
{
    int sockfd;
    struct sockaddr_in servaddr;

    if (argc != 2) {
        fprintf(stderr,"usage: udpcli <IPaddress>");
        exit(1);
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    
    sockfd = Socket(AF_INET, SOCK_DGRAM, 0);

    dg_cli(stdin, sockfd, (SA *)&servaddr, sizeof(servaddr));

    return 0;
}

static void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
    int n;
    char sendline[MAXLINE], recvline[MAXLINE + 1];

    while(Fgets(sendline, MAXLINE, fp) != NULL) {
        Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

        n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);

        recvline[n] = 0; /*null terminate */
        Fputs(recvline, stdout);
    }
}

static int Inet_pton(int af, const char *src, void *dst)
{
    int ret = inet_pton(af, src, dst);
    if (ret < 0) {
        perror("inet_pton");
        exit(1);
    }

    return ret;
}

static int Socket(int domain, int type, int protocol)
{
    int ret = socket(domain, type, protocol);
    if (ret < 0) {
        perror("socket error");
        exit(1);
    }
    return ret;
}

static ssize_t Recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
{
    int ret = recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
    if (ret < 0) {
        perror("recvfrom error");
        exit(1);
    }

    return ret;
}


static ssize_t Sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
{
    int ret = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
    if (ret < 0) {
        perror("sendto error");
        exit(1);
    }

    return ret;
}

static int Fputs(const char *s, FILE *stream)
{
    int ret = fputs(s, stream);
    if (ret == EOF) {
        fprintf(stderr, "fputs error");
        return -1;
    }
    return ret;
}

static char *Fgets(char *s, int size, FILE *stream)
{
    char *ret = fgets(s, size, stream);
    if (ret == NULL) {
        fprintf(stderr, "fgets error");
        return NULL;
    }
    return ret;
}

